using System;
using System.Threading;
using System.Windows.Documents;
using Microsoft.Practices.CompositeUI;
using NUnit.Framework;
using SCSFContrib.CompositeUI.WPF.Activation;

namespace SCSFContrib.CompositeUI.WPF.UnitTest.Activation
{
	[TestFixture]
	public sealed class FrameworkContentElementActivationServiceTest : UnitTest
	{
		private TestableRootWorkItem _workItem;
		private FrameworkContentElementActivationService _frameworkContentElementActivationService;

		protected override void SetUpCore()
		{
			base.SetUpCore();
			_workItem = new TestableRootWorkItem();
			_frameworkContentElementActivationService = new FrameworkContentElementActivationService(_workItem);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Constructor_ShouldThrowIfWorkItemIsNull()
		{
			_frameworkContentElementActivationService = new FrameworkContentElementActivationService(null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void FrameworkContentElementAdded_ShouldThrowIfFrameworkContentElementIsNull()
		{
			_frameworkContentElementActivationService.FrameworkContentElementAdded(null);
		}

		[Test]
		public void FrameworkContentElementAdded_ShouldntThrowIfFrameworkContentElementIsNonNull()
		{
			_frameworkContentElementActivationService.FrameworkContentElementAdded(new Hyperlink());
		}

		[Test]
		public void FrameworkContentElementAdded_ShouldWorkFromAnyThread()
		{
			Hyperlink hyperlink = null;

			Thread thread = new Thread(delegate()
			{
				hyperlink = new Hyperlink();
			});

			thread.SetApartmentState(ApartmentState.STA);
			thread.Start();
			thread.Join();

			Assert.IsNotNull(hyperlink);
			_frameworkContentElementActivationService.FrameworkContentElementAdded(hyperlink);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void FrameworkContentElementRemoved_ShouldThrowIfFrameworkContentElementIsNull()
		{
			_frameworkContentElementActivationService.FrameworkContentElementRemoved(null);
		}

		[Test]
		public void FrameworkContentElementRemoved_ShouldntThrowIfFrameworkContentElementIsNonNull()
		{
			_frameworkContentElementActivationService.FrameworkContentElementRemoved(new Hyperlink());
		}

		[Test]
		public void FrameworkContentElementRemoved_ShouldWorkFromAnyThread()
		{
			Hyperlink hyperlink = null;

			Thread thread = new Thread(delegate()
			{
				hyperlink = new Hyperlink();
			});

			thread.SetApartmentState(ApartmentState.STA);
			thread.Start();
			thread.Join();

			Assert.IsNotNull(hyperlink);
			_frameworkContentElementActivationService.FrameworkContentElementRemoved(hyperlink);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void GetIsExempt_ShouldThrowIfFrameworkContentElementIsNull()
		{
			FrameworkContentElementActivationService.GetIsExempt(null);
		}

		[Test]
		public void GetIsExempt_ShouldDefaultToFalse()
		{
			Assert.IsFalse(FrameworkContentElementActivationService.GetIsExempt(new Hyperlink()));
			Assert.IsFalse(FrameworkContentElementActivationService.GetIsExempt(new Underline()));
			Assert.IsFalse(FrameworkContentElementActivationService.GetIsExempt(new Run()));
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void SetIsExempt_ShouldThrowIfFrameworkContentElementIsNull()
		{
			FrameworkContentElementActivationService.SetIsExempt(null, false);
		}

		[Test]
		public void SetIsExempt_ShouldAssignGivenValue()
		{
			Hyperlink hyperlink = new Hyperlink();
			Underline underline = new Underline();

			FrameworkContentElementActivationService.SetIsExempt(hyperlink, true);
			FrameworkContentElementActivationService.SetIsExempt(underline, false);

			Assert.IsTrue(FrameworkContentElementActivationService.GetIsExempt(hyperlink));
			Assert.IsFalse(FrameworkContentElementActivationService.GetIsExempt(underline));
		}

		[Test]
		public void ActivateWorkItemForFrameworkContentElement_ShouldActivateWorkItem()
		{
			Assert.AreEqual(WorkItemStatus.Inactive, _workItem.Status);
			Assert.IsTrue(InvokePrivateMethod<bool>(_frameworkContentElementActivationService, "ActivateWorkItemForFrameworkContentElement", new Hyperlink()));
			Assert.AreEqual(WorkItemStatus.Active, _workItem.Status);
		}

		[Test]
		public void ActivateWorkItemForFrameworkContentElement_ShouldNotActivateWorkItemIfFrameworkContentElementIsExempt()
		{
			Hyperlink hyperlink = new Hyperlink();
			FrameworkContentElementActivationService.SetIsExempt(hyperlink, true);

			Assert.AreEqual(WorkItemStatus.Inactive, _workItem.Status);
			Assert.IsFalse(InvokePrivateMethod<bool>(_frameworkContentElementActivationService, "ActivateWorkItemForFrameworkContentElement", hyperlink));
			Assert.AreEqual(WorkItemStatus.Inactive, _workItem.Status);
		}
	}
}
